package scala.patternMatching

object MainOB {
   def main(args: Array[String]): Unit = {
      val x = new Var("x")
      val y = new Var("y")

      val unOP = new UnOp("+", x)
      println(unOP.toString())
      val sub = new UnOp("-", UnOp("-", x))
      println(sub.toString())
      val s = simplyTop(sub)
      println(s.toString())

      val l = List(2, 3, 4, 5, 6, 7, 8, 9, 10)
      demoMatch(l)
   }

   //case class pattern matching
   def simplyTop(ex: Expr): Expr = {
      ex match {
         case UnOp("-", UnOp("-", k))  => k
         case UnOp("+", UnOp("-", k))  => UnOp("-", k)
         case UnOp("-", UnOp("+", k))  => UnOp("-", k)
         case BinOp("+", Number(0), k) => k
         case BinOp("+", k, Number(0)) => k
         case BinOp("*", k, Number(1)) => k
         case BinOp("*", Number(1), k) => k
         case _                        => ex
      }
   }

   def demoMatch(l: List[Int]) = {
      l match {
         case List(1, _*) => println("OK , MATCH") // use _* to specify that when you do not know how long the List can be
         case _           =>
      }
   }
}

//define data type
abstract class Expr
case class Var(v: String) extends Expr {
   override def toString() = v
}
case class Number(n: Int) extends Expr {
   override def toString() = n.toString()
}
case class UnOp(op: String, right: Expr) extends Expr {
   override def toString() = op + "" + right.toString()
}
case class BinOp(op: String, left: Expr, right: Expr) extends Expr {
   override def toString() = left.toString() + " " + op + " 	" + right.toString()
}
